--╔════════════════════════════╗═════════════════════════════════════════════════════════════════════════════════════════════════#
--║      RAIL CAMERA HOOK      ║ The Camera stuff for when you get on rails. Can be easily overwritten with any other camera.
--╚════════════════════════════╝═════════════════════════════════════════════════════════════════════════════════════════════════#
local RAIL = GS_RAILS if RAIL.blockload return end
local SS2 = SPR2F_SUPER if SS2==nil SS2 = FF_SPR2SUPER or 0 end
/*local print = function(text) --Temporary debug
	if (consoleplayer) and consoleplayer==players[0] and consoleplayer.name=="Golden Shine" CONS_Printf(consoleplayer, text) end
end*/

--Account for hitbox differences and railswitching states!
--"so" is the source of the collision, likely a player mobj, but not always.
RAIL.RailCam = function(p, s, GS, STATS) if GS==nil return end 
	local CAM = GS.railcam local ghs = CAM --Because I'm stupid sometimes.
	local rail = GS.myrail or GS.LastRail or nil
	if not (rail) and type(CAM)=="userdata" and CAM.valid
		rail = CAM.lastrail or nil --Use either of these as our "rail"
	end
	if rail and ((rail.GSloopflags or 0) & 8388608) --Railcam forcibly disabled.
		if GS.railcam and GS.railcam.valid if p.awayviewmobj==GS.railcam p.awayviewmobj = nil end P_RemoveMobj(GS.railcam) end
		if GS.docam GS.docam = 0 end
		return --
	end
	local MAP = mapheaderinfo[gamemap]
	
	if GS.TWOD==true --No need for this in 2D mode.
		if MAP and (MAP.gsrailnorollintwod==true or MAP.gsrailnorollintwod=="true")
			--
		elseif GS.forcesprite==SPR2_ROLL or (s.sprite2&~SS2)==SPR2_ROLL
			s.rollangle = 0
		elseif rail and rail.GSrailsideL and rail.GSrailsideL.valid and rail.GSrailsideL.rollangle!=nil and not (GS.flipanim)
			local ANGDIFF = RAIL.AngleDifference(ANGLE_180, p.drawangle, 2, ANGLE_90, 2)
			if (ANGDIFF < ANGLE_22h) or (ANGDIFF > ANG1*68) --Only if they're actually facing the camera.
				local INVERT = (s.mirrored) and 1 or -1
				ANGDIFF = RAIL.AngleDifference(RAIL.ANG(rail), 0, 2, ANGLE_90, 2)
				if not (ANGDIFF > ANG30) INVERT = -$ end --Rails placed from right to left need this, apparently.

				s.rollangle = rail.GSrailsideL.rollangle*INVERT --Match rail angle exactly.
			end
		end
		if GS.railcam and GS.railcam.valid if p.awayviewmobj==GS.railcam p.awayviewmobj = nil end P_RemoveMobj(GS.railcam) end
		return --End it early.
	end
	local RO = p.GSRO if RO==nil return end --Need options setup at all times!
	
	local QUITCAM = false
	if MAP and MAP.gsrailcam and type(MAP.gsrailcam)=="string"
		local CAM = string.lower(MAP.gsrailcam)
		if CAM=="force"
			QUITCAM = "force" --Murder all other cameras.
		elseif CAM=="always"
			QUITCAM = "always" --Override player setting
		elseif CAM=="off" --Disable this camera always.
			if p.awayviewmobj==GS.railcam p.awayviewmobj,p.awayviewtics = nil,0 end
			if GS.railcam and GS.railcam.valid P_RemoveMobj(GS.railcam) end
			return --Nope.
		end
	end		
	
	local RO = p.GSRO
	if QUITCAM=="force" --Blow away everything that opposes us. Might not be a good idea.
		if p.solcam
			p.solcam.GSdisabled,p.solcam.emergencydisable = true, true
		end
		if (p.awayviewmobj!=GS.railcam) --Die.
			p.awayviewmobj,p.awayviewtics = nil,0
		end		
	else
		if p.solcam and mapheaderinfo[gamemap].solcam=="on" --Do we let Solcam win, or WE do it?
			if p.solcam.mode=="default" and not p.solcam.activetimer and not p.solcam.transitionrem
				if p.awayviewmobj==p.solcam.mobj
					p.awayviewmobj,p.awayviewtics = nil,0
				end
				p.solcam.GSdisabled = true
				p.solcam.emergencydisable = true
				if QUITCAM!="always"
					QUITCAM = false
				end
			else
				QUITCAM = true
			end
		end	
		if p.awayviewtics and not (p.awayviewtics==1 and p.awayviewmobj and p.awayviewmobj==GS.railcam) --Another custom cam is active!
		or QUITCAM==true
			if p.awayviewmobj==GS.railcam p.awayviewmobj,p.awayviewtics = nil,0 end
			return --
		end
	end

	local LOOP = RAIL.LearnLoopType(rail) --Function checks for rail validity, so it's safe.
	local FORCEANG,FRONTCAM = nil
	local LSIDECAM = 0,0
	local JUMPFLAGS,LOOPFLAGS,GRINDFLAGS = 0,0,0
	if rail
		JUMPFLAGS,LOOPFLAGS,GRINDFLAGS = rail.GSjumpflags or 0, rail.GSloopflags or 0,  rail.GSgrindflags or 0	
	end	
	if LOOPFLAGS or (LOOP and LOOP.walljump) --Loop has rail properties?
		if (LOOPFLAGS & 4194304) --Front camera.
			if not (GS.grinding) and (CAM and CAM.valid and CAM.FORCEANG!=nil)
				FORCEANG = CAM.FORCEANG
			else
				if GS.grinding
					GS.docam = max(GS.docam or 0, 12)
				end
				FRONTCAM = 0
				FORCEANG = p.drawangle+ANGLE_180
				if (LOOPFLAGS & 262144) and not (LOOPFLAGS & 524288)
					FRONTCAM = ANG2*14
					FORCEANG = $+ANG2*14 --From right diagional
				elseif (LOOPFLAGS & 524288) and not (LOOPFLAGS & 262144)
					FRONTCAM = -ANG2*14
					FORCEANG = $-ANG2*14 --From left diagional
				end
			end
		else --side camera?
			if (LOOPFLAGS & 262144) --Sidecam from right
				LSIDECAM = 1
			elseif (LOOPFLAGS & 524288) --Sidecam from left
				LSIDECAM = -1
			end
		end
		if LSIDECAM --Apply loopcams?
			if LSIDECAM==1 or LSIDECAM==-1 --Forced side-view camera?
				local NEWANG = RAIL.ANG(rail)
				if LOOP and LOOP.walljump
					if (rail.GSnextrail.z < rail.z)
						NEWANG = $+ANGLE_180
					end
					if GS.grinding
						NEWANG = $-(ANG2*2*LSIDECAM)
					end
				end
				FORCEANG = NEWANG-(ANGLE_90*LSIDECAM) --Use this angle.
				if LOOP and LOOP.walljump
					p.cmd.sidemove,p.cmd.forwardmove = 0,0
					GS.WJtag = NEWANG
					FORCEANG = $+(ANG2*LSIDECAM)
					if (CAM) and type(CAM)=="userdata" and CAM.valid
						p.cmd.angleturn = CAM.angle/FRACUNIT
						if GS.grinding and (GS.grinding <= 4)
							CAM.z = s.z
						end
					end
					if p.GSANflags==nil and not (p.pflags & PF_ANALOGMODE)				
						p.GSANflags = (p.pflags & (PF_DIRECTIONCHAR|PF_ANALOGMODE))
						p.pflags = $|PF_DIRECTIONCHAR|PF_ANALOGMODE
					end
				else
					GS.WJtag = nil
				end
				if GS.grinding and not GS.leftrail
					GS.nocam = 0
				end					
			end
		end
	end
	if FORCEANG==nil
		if GS.walljump and not (CAM) and (GS.walljump.timer)
			return --
		elseif LOOP and LOOP.walljump --Remove camera on walljump rails that don't have loopcams applied.
			GS.WJtag = nil
			if GS.docam GS.docam=0 end 
			if GS.railcam and GS.railcam.valid P_RemoveMobj(GS.railcam) end return --			
		elseif not ((CAM) and type(CAM)=="userdata" and CAM.valid and (CAM.FORCEANG!=nil))
			if RO.cam_vanilla and (QUITCAM!="always") --Player wants the vanilla camera, but a mapper's preference takes priority.
			or GS.nocam --Cam should be disabled temporarily.
			or GS.ropesnap and rail==GS.ropesnap and not (LOOPFLAGS & (262144|524288))
				if p.awayviewmobj==GS.railcam p.awayviewmobj,p.awayviewtics = nil,0 end
				return --
			end
		end
	end 
	local FREEVAIM = ((GS.OGAIM!=nil) and not (LOOP) and not (LSIDECAM)) and 1 or 2 --Vertical aim?
	local RSTATS = GS.MyRailStats
	local ME = ((p==displayplayer) and (p==consoleplayer)) and p or nil
	local MAXCAM = 54 --How far the camera can be from us.
	local BUFFERMAX = MAXCAM+23	 --BUFFER.
	
	--Special Camera Setup.
	local MOMANG = p.cmd.angleturn<<16 
	local RAILANG = p.drawangle
	if rail
		RAILANG = RAIL.ANG(rail)
		MOMANG = RAILANG+GS.raildirection
		if FRONTCAM!=nil and FORCEANG!=nil
			FORCEANG = (MOMANG+ANGLE_180)+FRONTCAM
		end
	end
	if not (CAM and CAM.valid)
		CAM = P_SpawnMobjFromMobj(s, 0,0,-s.momz, MT_THOK)
		CAM.flags = MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOSECTOR|MF_NOCLIPHEIGHT
		CAM.flags2 = MF2_DONTDRAW
		P_TryMove(CAM, CAM.x-s.momx, CAM.y-s.momy, true)
		CAM.lastx,CAM.lasty,CAM.lastz = s.x,s.y,s.z	
		CAM.zspeed = 6*s.scale --start with a bit of lag.
		p.awayviewaiming = p.aiming/FREEVAIM
		CAM.PlastZ = s.z-s.momz
		CAM.spawntic = true
		CAM.init = 1
		CAM.straightway = 3
		if GS.chasecam==true and (netgame!=true) and p==ME and camera 
			CAM.angle = camera.angle
			CAM.radius = camera.radius
			CAM.height = camera.height
			CAM.momx,CAM.momy,CAM.momz = camera.momx,camera.momy,(camera.momz*2)
			P_SetOrigin(CAM, camera.x-camera.momx, camera.y-camera.momy, camera.z+camera.momz)
		else
			CAM.angle = p.cmd.angleturn<<16
			CAM.radius,CAM.height = 24*s.scale,18*s.scale
			CAM.momx,CAM.momy,CAM.momz = s.momx,s.momy,s.momz
		end
		if GS.lastPang==nil
			 GS.lastPang = p.cmd.angleturn<<16
		end
		CAM.camdist = RO.cam_dist+((p.pflags & PF_ANALOGMODE) and 18 or 0)
		CAM.camheight = RO.cam_height+((p.pflags & PF_ANALOGMODE) and 9 or 0)
		CAM.startheight = CAM.camheight
		GS.railcam = CAM
	end
	CAM.scale,CAM.radius,CAM.height = s.scale,24*s.scale,18*s.scale --Adjust size!
	CAM.init = $+1 --How long you've existed.
	CAM.lastrail = rail
	if CAM.camheight == nil or CAM.camdist==nil or GS.grinding==2
		CAM.camdist = RO.cam_dist+((p.pflags & PF_ANALOGMODE) and 18 or 0)
		CAM.camheight = RO.cam_height+((p.pflags & PF_ANALOGMODE) and 9 or 0)
		if GS.grinding==2 --Reset some stuff if we JUST started grinding again.
			CAM.straightway = 3
			CAM.turning = 0
			CAM.flags = MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOSECTOR|MF_NOCLIPHEIGHT
			CAM.loopCstart,CAM.loopstart,CAM.loopcam,CAM.CAMfXY,CAM.stress = nil
		end
	elseif CAM.stress
		CAM.stress = max($-1,0)	
	end		
	if CAM.restoreANG!=nil
		if not (CAM.loopCstart) CAM.angle = CAM.restoreANG end
		CAM.restoreANG = nil
	end
	local DIST = (CAM.warptic) and (9999<<16) or FixedHypot(FixedHypot(s.x-CAM.x, s.y-CAM.y), s.z-CAM.z)
	local MAXDIST = (((1111+RO.cam_dist)*s.scale)+(abs(GS.railspeed or 0)*2))		
	if GS.railswitching or (LOOPFLAGS & 16777216)
		CAM.loopCstart,CAM.loopstart,CAM.loopcam,CAM.CAMfXY = nil
		CAM.momx,CAM.momy,CAM.momz = s.momx*4/5,s.momy*4/5,0
		if (LOOPFLAGS & (4194304|16777216))
			CAM.FORCEANG,CAM.restoreANG = nil
			if FORCEANG!=nil
				CAM.angle = FORCEANG
			end
		end	
	elseif (netgame!=true) and GS.chasecam==true and (p==players[1] and camera2 or p!=players[1] and camera)
	//and p==ME //camera and camera.chase
		if p==players[1]
			if (DIST > MAXDIST) and not (CAM.loopCstart) P_MoveOrigin(CAM, camera2.x, camera2.y, camera2.z) end
			CAM.momx,CAM.momy,CAM.momz = camera2.momx,camera2.momy,0
		else
			if (DIST > MAXDIST) and not (CAM.loopCstart) P_MoveOrigin(CAM, camera.x, camera.y, camera.z) end
			CAM.momx,CAM.momy,CAM.momz = camera.momx,camera.momy,0		
		end
	else
		if (DIST > MAXDIST) and not (CAM.loopCstart) P_MoveOrigin(CAM, s.x, s.y, (s.z-s.momz)+s.height) end
		CAM.momx,CAM.momy,CAM.momz = 0,0,0
	end
	if CAM.warptic
		CAM.warptic = max($-1,0)
	end
	CAM.lastx,CAM.lasty,CAM.lastz = CAM.x,CAM.y,CAM.z //s.x,s.y,s.z
	
	--Now zoom out the camera
	MAXDIST = RO.cam_dist + ((p.pflags & PF_ANALOGMODE) and 56 or 38)
	if LSIDECAM==1 or LSIDECAM==-1  --Sidecam!
		CAM.flags = $|MF_NOCLIPHEIGHT
		CAM.loopCstart,CAM.CAMfXY = nil
		if CAM.FORCEANG!=nil and GS.grinding
			CAM.sidecam = LSIDECAM
			if LOOP
				MAXDIST = max(385, $)
				if LOOP.walljump
					CAM.momz = $/9
					CAM.zspeed = 44*s.scale
					local SETX,SETY,SETZ = CAM.x, CAM.y, CAM.z
					SETZ = s.z-( (abs(s.momz)-32*s.scale )*P_MobjFlip(s))					
					if (GS.grinding < 4) and FORCEANG!=nil and rail.GSVertRailDOWNANG!=nil
						P_TryMove(CAM, 
						CAM.x+FixedMul(64*s.scale, cos(rail.GSVertRailDOWNANG)),
						CAM.y+FixedMul(64*s.scale, sin(rail.GSVertRailDOWNANG)), true)			
					end
					P_TryMove(CAM, SETX, SETY, true) 
					P_MoveOrigin(CAM, CAM.x, CAM.y, SETZ)
				else
					local GSPEED = abs(GS.railspeed or 0)
					p.awayviewaiming = $/2
					p.aiming = $/2
					CAM.zspeed =  max(GSPEED*3/4, 36*s.scale)
					CAM.camdist = max(CAM.camdist or 0, 198+(GSPEED/(2*s.scale)))
					if RSTATS and RSTATS.VERTRAIL 
						CAM.noZ = 0
						if ((RSTATS.ZSPEED or 0) < 0) --Going down. Catch them, camera!
							CAM.zspeed =  $+(GSPEED/5)
						elseif (RSTATS.INIT < 5) --Stay still for a sec!
							CAM.noZ = 2
						end
					end
				end
			end
			CAM.camdist = max(CAM.camdist or 0, 240)
		elseif GS.walljump and ((GS.walljump.init or 0)<10)
			CAM.zspeed =  $/(11-GS.walljump.init) --Lag Z-cam a bit.
		end
	elseif LOOP and not (LOOP.walljump) and not (LOOPFLAGS & 4194304) --Loop camera
		if (abs(GS.railspeed or 0) > 45*s.scale) or rail.GSconveyor
		or (LOOPFLAGS & 131072) and not (rail and rail.GSVertRail) 
			CAM.boot = 21
		elseif CAM.boot
			CAM.boot = $-1
			if not CAM.boot and GS.grinding
				CAM.noZ = 0
				CAM.camdist = min(CAM.camdist or 0, 220)
			end
		end
		if not (CAM.boot)
			CAM.loopCstart,GS.holdF,CAM.loopcam,CAM.CAMfXY = nil
			CAM.flags = $ & ~(MF_NOCLIPHEIGHT|MF_NOCLIP)
		else
			CAM.flags = $|MF_NOCLIP|MF_NOCLIPHEIGHT
			if CAM.loopCstart!=false and (abs(GS.railspeed) > 16*s.scale)
				if CAM.loopCstart==nil CAM.loopCstart = "start" end
				if (CAM.loopCstart)
					CAM.momx,CAM.momy = 0,0
					if (LOOPFLAGS & 131072)
						if CAM.loopCstart=="start"
							CAM.turning = 0
							CAM.angle = MOMANG
							CAM.instaturn = max(CAM.instaturn or 0, 2)
						end
						CAM.loopCstart = "unlock"
						CAM.zspeed = max($, max((GS.railspeed or 0)*3/4, 48*s.scale))
					elseif CAM.loopCstart == "unlock"
						CAM.loopCstart = false
						GS.holdF = true
					end
				end
			end
			if CAM.loopcam
				MAXDIST = $+ (CAM.loopcam*((CAM.gainingloop==true) and 31 or 12))
				if CAM
					if (LOOPFLAGS & 131072)
						CAM.noZ = max(CAM.noZ and 0, 2)
					elseif LOOP.anim==0 and (abs(GS.railspeed or 0) > 21*s.scale)
						CAM.noZ = 0
					end
				end
			else
				MAXDIST = $+min(abs(GS.railspeed or 0)/4, 12)
			end
		end		
	elseif (LOOPFLAGS & 4194304) and (FORCEANG!=nil) --Front camera
		local SPED = abs(GS.railspeed or 0)/s.scale
		if (LOOPFLAGS & (262144|524288))
			SPED = $+64
		end
		CAM.angle = FORCEANG
		CAM.flags = $|MF_NOCLIPHEIGHT
		CAM.loopCstart,CAM.CAMfXY = nil
		MAXDIST = max(240+SPED, $+SPED)
		CAM.camdist = max(CAM.camdist or 0, 175+SPED)		
	else
		CAM.flags = $ & ~MF_NOCLIPHEIGHT
		if (CAM.sidecam or CAM.boot) and not (LOOP)
			CAM.camdist = RO.cam_dist+((p.pflags & PF_ANALOGMODE) and 18 or 0)
			CAM.camheight = RO.cam_height+((p.pflags & PF_ANALOGMODE) and 9 or 0)
			CAM.straightway = 3
			CAM.turning = 0
			CAM.flags = MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOSECTOR|MF_NOCLIPHEIGHT	
			CAM.loopCstart,GS.holdF,CAM.loopcam,CAM.CAMfXY,CAM.boot,CAM.sidecam,CAM.stress = nil
		end
	end
	if (CAM.camdist < MAXDIST)
		local ADD = (abs(GS.railspeed or 0)>90*s.scale) and 2 or (abs(GS.railspeed or 0)>50*s.scale) and 1 or 0

		CAM.camdist = min(MAXDIST, ($ < (MAXDIST-35)) and $+4+ADD or ($ < (MAXDIST-30)) and $+3+ADD
		or ($ < (MAXDIST-25)) and $+2+ADD or $+1+ADD)
	end	
	CAM.eflags = s.eflags
		
	ghs = CAM --Because I'm stupid.
	CAM.fuse,CAM.tics = 2,2 --Keep camera alive.
	if FORCEANG!=nil and (CAM.FORCEANG==nil or LOOP and LOOP.walljump) --Setting up FORCEANG?
		CAM.angle = FORCEANG
		if not GS.grinding and (LOOPFLAGS & 4194304)
			CAM.FORCEANG = nil
		else
			CAM.FORCEANG = FORCEANG	
		end
		CAM.loopcam = nil --Not the same loopcam!
	elseif CAM.FORCEANG!=nil
		CAM.momz = $/8
		if FORCEANG==nil and not (LOOP)
			CAM.FORCEANG = nil
		end
	end
	if not (LSIDECAM) and not (LOOPFLAGS & 16777216)
		if RSTATS and RSTATS.VERTRAIL
			local STEP = min(abs(GS.railspeed or 0)/3, 24*s.scale)
			CAM.z = s.z-(STEP*P_MobjFlip(s))
		elseif (CAM.init%3==0) and CAM.camheight!=nil and (CAM.camheight < (CAM.startheight+7))
			CAM.camheight = $+1 --Raise slightly. Rise slightly.
		end
		
		local FLOORZ = CAM.floorz
		local MAXCEILINGZ = CAM.ceilingz-(32*s.scale)
		if (LOOP and not LOOP.walljump) or CAM.loopcam
			MAXCEILINGZ = max(s.z, min($-(96*s.scale), s.ceilingz-(128*s.scale)) )
			FLOORZ = min(s.z+48*s.scale, FLOORZ+48*s.scale)
			if (CAM.camdist < 370)
				CAM.camdist = $+(abs(GS.railspeed or 0)/(4*s.scale))
			end
			CAM.turning,CAM.stress,CAM.turnstress = 0,0,0
			CAM.PostANG = "face"	
		end
		if (CAM.z > MAXCEILINGZ) and not (FLOORZ > MAXCEILINGZ)
			P_MoveOrigin(CAM, CAM.x, CAM.y, MAXCEILINGZ)
		end
		if (CAM.z < FLOORZ) and not (FLOORZ > MAXCEILINGZ)
			P_MoveOrigin(CAM, CAM.x, CAM.y, FLOORZ+1)
		end
	end
	
			
/*	if (netgame==true)
		if ((GS.grinding or 0) > 2) or GS.railswitching or GS.docam or (LOOPFLAGS & 16777216)
			p.awayviewtics = 2
			p.awayviewmobj = CAM --Use THIS as the camera.
		end
	else */
		if GS.chasecam==true or (LSIDECAM) or (LOOPFLAGS & 4194308) or (LOOP and not LOOP.walljump) //if camera and camera.chase
			if ((GS.grinding or 0) > 2) or GS.railswitching or GS.docam or (LOOPFLAGS & 16777216)
				p.awayviewtics = 2
				p.awayviewmobj = CAM
			end
		else
			p.awayviewtics,p.awayviewmobj = 0,nil		
			CAM.fuse,CAM.tics = 1,1
			if GS.grinding and not (GS.chasecam==false) --Since we're gonna snap anyway, do this.
				p.cmd.angleturn = p.drawangle/FRACUNIT
			end
		end
--	end
	
	local HANG = (RAIL.GrindState(s, "hang")) and true or false
	local DESTZ = ((CAM.camheight or 0)*s.scale)/((HANG==true) and 3 or 1)
--	local MOVEDGOHAN = false
	if GS.railswitching or (LOOPFLAGS & 16777216)
		if (GS.railswitching == 7) or (LOOPFLAGS & 16777216)
			CAM.momx,CAM.momy = $/2,$/2
		end
		p.cmd.buttons = $ & ~(BT_CAMLEFT|BT_CAMRIGHT)
		CAM.warptic,CAM.spawntic,CAM.turning = nil return CAM --
	elseif CAM.FORCEANG==nil
		local REVERSING = false
		if GS.myrail and GS.railspeed!=nil
			if ((GS.railspeed > 0) and MOMANG == RAILANG)
			or ((GS.railspeed <= 0) and MOMANG == RAILANG+ANGLE_180)
				REVERSING = true
			end
		end
		local DESTAIM = p.awayviewaiming
		if LOOP and not (LOOPFLAGS & 131072) and RSTATS and RSTATS.VERTRAIL --Loop camera!
		and (abs(RSTATS.ZSPEED or 0) > s.scale*6) and not (LSIDECAM)
			if not (CAM.loopstart)
				CAM.turning = 0
				CAM.loopstart = (RSTATS.ZSPEED < 0) and -1 or 1
			end
			local ADD = max(2, min(5, abs(RSTATS.ZSPEED)/(s.scale*4)) )
			local CAMADD = GS.camadd or 0				
			CAM.loopcam = min(48, CAM.loopcam and $+ADD or ADD)
			CAM.gainingloop = false
			local SHIFT = RSTATS.ZSPEED*11
		--	print("LOOPSTART:\x88"+CAM.loopstart+"\x80 CAMADD:\x84"+CAMADD/ANG1)
			if (RSTATS.ZSPEED < 0) --Going down
				p.awayviewaiming = min(ANG2, max(-ANG20, $-(SHIFT*3/4)) )
				if CAM.loopstart==1 and GS.camdir==1
					CAMADD = $*2/3
					GS.camdir = -1
					CAM.loopstart = -1
				end
				CAM.noZ = 0
				if (CAM.z > s.z)
					local OGMOMZ = CAM.momz
					CAM.momz = -abs(RSTATS.ZSPEED)
					P_SceneryZMovement(CAM)
					if not (CAM and CAM.valid) return end --
					CAM.momz = OGMOMZ
				end				
			else --Going up.
				CAMADD = max(ANG1, min(ANG1*34, $+(abs(SHIFT)*2)))
				p.awayviewaiming = min(ANG1*69, $+SHIFT)
				CAM.gainingloop = true
				CAM.noZ = CAM.loopcam+12
				GS.camdir = 1
				if (CAM.z+(256*s.scale) < s.z)
					local OGMOMZ = CAM.momz
					CAM.momz = abs(RSTATS.ZSPEED/3)
					P_SceneryZMovement(CAM)
					if not (CAM and CAM.valid) return end --
					CAM.momz = OGMOMZ
				end
			end
			GS.camadd = CAMADD
	
		elseif not ((CAM.loopcam and (CAM.loopcam > 11) or CAM.loopCstart) and LOOP)
		
			if not (LOOP) and CAM.loopstart
				CAM.loopstart,CAM.noZ,CAM.loopcam = nil
				CAM.flags = $ & ~(MF_NOCLIPHEIGHT|MF_NOCLIP)
			end
			if GS.myrail and GS.myrail.GSrailZDelta and ((GS.myrail.GSrailZDelta/(ANG1*3))!=0)
				local ZDIFF = GS.myrail.GSrailZDelta
				if ((GS.railspeed or 0)<0) 
					ZDIFF = InvAngle($)
				end
				if REVERSING==true
					ZDIFF = InvAngle($)
				end
			--	print("Reverse:\x84"+REVERSING+" TMOMZ:\x82"+TMOMZ)
				if HANG==true
					if (ZDIFF < 0) --Adjust to slope.
						DESTAIM = -(max(-ANG1*35, ZDIFF/2) )
					else
						DESTAIM = -(min(ANG1*35, ZDIFF/2))
					end			
					ZDIFF = abs(($/(ANG1/2)))*s.scale
					DESTZ = $+(ZDIFF*3)
				else
					if (s.eflags & MFE_VERTICALFLIP)
						if (ZDIFF < 0) --Adjust to slope.
							DESTAIM = -(max(-ANG1*35, ZDIFF/2) )
						else
							DESTAIM = -(min(ANG1*27, ZDIFF/4))
						end					
					else
						if (ZDIFF < 0) --Adjust to slope.
							DESTAIM = -(max(-ANGLE_22h, ZDIFF/4) )
						else
							DESTAIM = -(min(ANG1*43, ZDIFF))
						end	
					end
					ZDIFF = ($/(ANG1/4))*s.scale
					local LASTZ = GS.LastGrindZ if LASTZ==nil LASTZ = s.z end
					local TMOMZ = s.z-LASTZ
					if ((GS.grinding or 0) < 14) --Initially be fast as fuck, boi
						CAM.zspeed = max($, 333*s.scale + abs(TMOMZ) )
					else
						local ZSPEED = (((ZDIFF<0) and 12 or 8)*s.scale) + abs(TMOMZ) + (abs(DESTAIM/ANG1)*s.scale)
						if (DESTAIM < -8*ANG1) or (DESTAIM > ANG10)
							ZSPEED = (DESTAIM < -ANG20) and $*3 or (DESTAIM < -14*ANG1) and $*2 or $*3/2
						end
						if s.GScollide and type(s.GScollide)=="userdata" and s.GScollide.valid and (s.GScollide.flags & MF_SPRING)
							ZSPEED = $+(80*s.scale)
						end
						CAM.zspeed = max($, ZSPEED)
					end					
					DESTZ = $+abs(TMOMZ)+max(-abs(TMOMZ), ZDIFF*3)					
				end			
			else
				if (abs(DESTAIM) <= (ANG1+(ANG1/3)))
					DESTAIM = 0
				else
					DESTAIM = $/2 //(abs(DESTAIM) <= ANG30) and $*2/3 or 
				end
			end
		end
		if FREEVAIM==1
			DESTAIM = p.aiming
		elseif DESTAIM!=p.awayviewaiming --Default camera behaviour.
			local ADD = (CAM.spawntic) and ANG1*3 or ANG1/5
			local ZDIFF = abs(abs(DESTAIM)-abs(p.awayviewaiming))
			if (ZDIFF > ANG2*2) --Sudden sharp difference? Speed up a bit.
				ADD = (ZDIFF > ANG2*4) and max(ANG1*3, $*9) or max(ANG1, $*3)
			end
			if (DESTAIM > p.awayviewaiming)
				p.awayviewaiming = min(DESTAIM, $+ADD) 
			else--if (DESTAIM < p.awayviewaiming)
				p.awayviewaiming = max(DESTAIM, $-ADD) 
			end			
			p.aiming = p.awayviewaiming	
		end
	end
	if CAM.FORCEANG!=nil 
		if GS.grinding and not (LOOP)
			if (LOOPFLAGS & 4194304)--Front camera?
			--	if FORCEANG!=nil
			--		CAM.FORCEANG = FORCEANG
			--	end
			--	CAM.angle,CAM.turning = CAM.FORCEANG,0 --Using Center Cam!		
			elseif (LSIDECAM)
				if FORCEANG!=nil
					CAM.FORCEANG = FORCEANG
				else
					CAM.FORCEANG = CAM.angle
				end
			end
		end
	 --Forcing Camera Angle through a 2D loopcam, probably.
	elseif (netgame!=true)
	and ((p==players[0] and input.gameControlDown(GC_CENTERVIEW)) or (p==players[1] and input.gameControl2Down(GC_CENTERVIEW))) --Single Player only, unfortunately.
	or ((CAM.stress or 0)> 10) and ((CAM.turning or 0) < 8) and not (LOOP) and not (CAM.loopCstart) --Snap camera!
	or CAM.instaturn
	
		if not (LSIDECAM) and ((CAM.stress or 0)> 10) 
			GS.camdir = (GS.camdir==-1) and 1 or -1
			if not (LOOPFLAGS & 4194304)
				GS.invertinput = 1
			end
		end
		CAM.stress = 0
		CAM.angle,CAM.turning = MOMANG,0 --Using Center Cam!
		
	elseif RO.cam_turnspeed==7778 --Perma-Center.
	
		CAM.angle,CAM.turning = MOMANG,0 --Using Center Cam! 
		
		--Camera sideways angle adjustment.
	elseif GS.lastPang!=nil --Is the player spinning the camera?
	
		local ROTSPEED = (RO.cam_autoturnspeed==100) and ANG1 or (ANG1/100)*(RO.cam_autoturnspeed or 1)
		local CAMLR = (p.cmd.buttons & BT_CAMLEFT) and 1 or (p.cmd.buttons & BT_CAMRIGHT) and -1 or 0
		if RO.cam_turnspeed==7777
			CAM.turning = 0
		elseif CAMLR==0
			if (splitscreen) and p==players[1]
				if input.gameControlDown(GC_TURNLEFT)
					CAMLR = 1
				elseif input.gameControlDown(GC_TURNRIGHT)
					CAMLR = -1
				end
			elseif (netgame!=true) and p==ME 
				if input.gameControlDown(GC_TURNLEFT)
					CAMLR = 1
				elseif input.gameControlDown(GC_TURNRIGHT)
					CAMLR = -1
				end
			end
		end
		
		local SWAPINIT = 99 if GS.ANGswap SWAPINIT = GS.ANGswap.init or 0 end --Did we just turn?
		if ((CAM.turning or 0) > 8) or (SWAPINIT < 7)
			CAM.straightway = 0
		end
		local DIDSUPERTURN = false
		local ANG,PLUS = RAIL.AngleDifference(MOMANG, CAM.angle, 2, ANG60, 2)
				
		if not (LOOP and not (LOOP.walljump))
		and not (LSIDECAM) and not (CAM.loopCstart)
		and not (ANG < ANG1)
		and not (rail and rail.GSVertRail and not LOOP)
		
			if GS.crouchgrind or (p.cmd.buttons & (BT_SPIN|BT_CUSTOM1)) 
			or ((GS.railfalltimer or 0) > 13)
			or (p.pflags & PF_FORCESTRAFE)
			or GS.failroll
			or (abs(p.cmd.forwardmove) > 37) // or (abs(p.cmd.sidemove) > 37) and (CAMLR!=0) and not (p.pflags & PF_ANALOGMODE)
			or ((GS.grinding or 0) < 5) and (abs(GS.railspeed or 0) > 34*s.scale)
			or CAM.superturn and not ((CAM.turning or 0) > 7)
			
				if (p.cmd.buttons & (BT_SPIN|BT_CUSTOM1)) or (abs(p.cmd.forwardmove) > 37)
					ROTSPEED = (RO.cam_centerspeed==100) and ANG1 or (ANG1/100)*RO.cam_centerspeed
				end
					
				if (SWAPINIT < 9) and not ((CAM.turning or 0)>8) and not ((GS.railfalltimer or 0) > 13)
					ROTSPEED =  (SWAPINIT > 6) and $*3/4 or (SWAPINIT > 3) and $*4/5 or $*5/6 --Smoothen things a bit.
					CAM.straightway = 0
				else
					CAM.straightway = $+1
					if (CAM.straightway > 2)
						ROTSPEED = (CAM.straightway > 12) and $*2 or (CAM.straightway > 7) and $*3/2 or $*4/3
					end
				end				
		--		print("Cam.straightway:\x83"+CAM.straightway+"\x80 SWAPINIT:\x84"+SWAPINIT)
				local ANG,PLUS = RAIL.AngleDifference(MOMANG, CAM.angle, 2, ANG60, 2)
				if ((GS.railfalltimer or 0) > 13) --This is important!
					ROTSPEED = max($, ANG1)
					CAM.turnstress = max(CAM.turnstress or 0, 70)
				end
				local RSPED = ROTSPEED
				if ((CAM.turnstress or 0) > 52)
					local TEMP = RSPED/156
					TEMP = FixedDiv(FixedMul($, min(156, 52+(CAM.turnstress-52))), 52)
					RSPED = max($, TEMP*156)
				end			
				DIDSUPERTURN = true
				
				if (ANG > max(ANG1*17, ROTSPEED*17)) or CAM.superturn and (ANG > ANG2)
					local MAXNO = 2+(abs(p.cmd.sidemove or 1)/16)
					if ((GS.turntoia or 0) > MAXNO)
						CAM.angle = (ANG > ROTSPEED*43) and $+(RSPED*4*PLUS) or $+(RSPED*3*PLUS)
					else
						CAM.angle = $+( min(12, max(ANG/6, 4))*PLUS*RSPED)
					end
					CAM.turnstress = CAM.turnstress and $+4 or 4
				elseif (ANG > max(ANG1*7, ROTSPEED*7))
					CAM.angle = $+(RSPED*3*PLUS)	
					CAM.turnstress = CAM.turnstress and $+3 or 3
				else
					if (ANG > max(ANG2, RSPED*2))
						CAM.angle = $+(RSPED*2*PLUS)
						CAM.turnstress = CAM.turnstress and $+2 or 2
					elseif RO.cam_turnspeed==7777
						CAM.angle,CAM.turning = MOMANG,0
					else
						DIDSUPERTURN = false
						CAM.superturn = 0
					--	CAM.angle = MOMANG
					end
				end
				CAM.turning = min(9, max( (CAM.turning or 0)-3 , 0))
				if ((GS.railfalltimer or 0) > 13) and (ANG < ANGLE_22h)
					CAM.angle,CAM.turning = MOMANG,0
					CAM.instaturn = 2
					DIDSUPERTURN = true
				end				
			end
		end	
		if DIDSUPERTURN==false
			if RO.cam_turnspeed==7777
				CAM.turning = 0
			elseif (CAMLR!=0)
				ROTSPEED = (RO.cam_turnspeed==100) and ANG1 or (ANG1/100)*RO.cam_turnspeed
				
				CAM.turning = CAM.turning and $+1 or 1
				local MULT = max(1, min(4, CAM.turning/3))
				CAM.angle = $+(ROTSPEED*MULT*CAMLR)	
				
			else		
				if (abs(p.cmd.sidemove) > 11) and not ((GS.grinding or 0) < 4) and not (abs(p.cmd.forwardmove) > 22)
					ROTSPEED = (RO.cam_turnspeed==100) and ANG1 or (ANG1/100)*RO.cam_turnspeed
					
					CAM.turning = CAM.turning and $+1 or 1
					local MIN = max(11, 34-(CAM.turning*2))
					local ROT = (ROTSPEED/MIN)*p.cmd.sidemove
					if CAM.dimROD ROT = ($/6)*7 end
					CAM.angle = $-ROT

				else --Automatic cam angle adjustment?
					if not ((CAM.turning or 0)>8)
						if (SWAPINIT < 9)
							CAM.straightway = 0
							ROTSPEED =  (SWAPINIT > 6) and $*2/3 or (SWAPINIT > 4) and $*3/4 or $*4/5 --Smoothen things a bit.
						else
							CAM.straightway = $+1
							if (CAM.straightway > 5)  --Speed up after a bit.
								ROTSPEED = (CAM.straightway > 15) and $*3/2 or (CAM.straightway > 10) and $*4/3 or $*5/4
							end
						end
					end
					if not (RO.cam_autoturnspeed==0)
		--				print("\x84"+"AUTO:\x80 Cam.straightway:\x84"+CAM.straightway+"\x80 SWAPINIT:\x87"+SWAPINIT)
						local SPEED = abs(GS.railspeed or 0)/s.scale
						local ANG,PLUS = RAIL.AngleDifference(MOMANG, CAM.angle, 2, ANG60, 2)
						local ROT = min(ROTSPEED*4/3, (ROTSPEED/11)*SPEED)
						if (ROT >= ANG/4)
							ROT = (ANG>ANG1/2) and max(1, ANG/2) or max(1, ANG/4)				
						end
						if ((CAM.turnstress or 0) > 60)
							local TEMP = ROT/180
							TEMP = FixedDiv(FixedMul($, min(150, 60+(CAM.turnstress-60))), 60)
							ROT = max(ROT, TEMP*180)
						end
						if CAM.dimROD and (CAM.dimROD.div or 0) > 1
							ROTSPEED = ($*2)/CAM.dimROD.div
							if RSPED RSPED = ($*2)/CAM.dimROD.div end
							CAM.dimROD.div = $-1
						end
					--	if (ANG > ROT)
					--		ANG = max(0, $+(abs(p.cmd.sidemove)*ANG1)+((GS.turntoia or 0)*ANG2) )
					--	end
						if (ANG > max(ANG1*27, ROT*27))
							if (ANG > ANG1*38)
								CAM.angle = (ANG > ANG1*47) and $+((ROT*5)*PLUS) or $+((ROT*4)*PLUS) --	print("\x82 4")	
								CAM.turnstress = CAM.turnstress and $+5 or 5
							else
								CAM.angle = $+((ROT*3)*PLUS) --print("\x82 3")	
								CAM.turnstress = CAM.turnstress and $+4 or 4
							end
						elseif (ANG > max(ANG1*5, ROT*5))
							CAM.angle = (ANG > ANG1*13) and $+((ROT*2)*PLUS) or $+((ROT+(ROT/2))*PLUS) --  print("\x81 2")	
							CAM.turnstress = CAM.turnstress and $+3 or 3
						else
							if (ANG > max(ANG1/4, ROT))
								if (ANG > ANG2)
									CAM.turnstress = CAM.turnstress and $+2 or 2
									CAM.angle = $+(ROT*PLUS)
								else
									CAM.angle = $+((ROT/2)*PLUS) -- print("\x84 1")
								end
							else
								CAM.angle = MOMANG 
								if CAM.turnstress
									CAM.turnstress = max(0, ($/2)-2)
								end
						--		print("This one! CAM.angle:\x82"+MOMANG/ANG1+" TIME:"+leveltime)
							end
						end
					--	print("TURNSTRESS:\x82"+CAM.turnstress+"\x80 ROT:\x81"+(ROT/(ANG1/10)))
					end
					CAM.turning = min(9, max( (CAM.turning or 0)-3 , 0))
				end
			end
		end
	end
	
	--Vertical camera position auto-adjustment.
	if not (CAM.noZ)
		if HANG==true
			DESTZ = s.z+(-abs($)*P_MobjFlip(s)) 
		else
			DESTZ = s.z+(abs($)*P_MobjFlip(s))		
		end
		if (s.eflags & MFE_VERTICALFLIP)
			if HANG==true and (CAM.z < s.z)
				P_MoveOrigin(CAM, CAM.x, CAM.y, s.z)
				DESTZ = max(s.z+48*s.scale, $)
			end
			if (CAM.floorz > DESTZ)
				DESTZ = CAM.floorz+1
			end
		else
			if HANG==true and (CAM.z > s.z)
				P_MoveOrigin(CAM, CAM.x, CAM.y, s.z)
				DESTZ = min(s.z-48*s.scale, $)
			end
			if (CAM.ceilingz < DESTZ)
				DESTZ = CAM.ceilingz-1
			end
		end
		if (DESTZ <= CAM.z)
			P_MoveOrigin(CAM, CAM.x, CAM.y, max(DESTZ, CAM.z-CAM.zspeed))
		elseif (DESTZ > CAM.z)
			P_MoveOrigin(CAM, CAM.x, CAM.y, min(DESTZ, CAM.z+CAM.zspeed))
		end	
	end
	
	if not CAM.warptic and CAM.loopCstart==nil and not (LOOP) --Let's check if the camera gets stuck.
		local X,Y,Z = CAM.x,CAM.y,CAM.z
		if not P_TryMove(CAM, CAM.x+FixedMul(240*s.scale, cos(MOMANG)), CAM.y+FixedMul(240*s.scale, sin(MOMANG)), true) 
			CAM.warptic = 1
		else
			P_MoveOrigin(CAM, X, Y, Z)
		end
	end
	
	--Set camera's proper position behind us.
	local ANGCAM = CAM.angle if CAM.FORCEANG!=nil ANGCAM = CAM.FORCEANG end
	local CAMDIST = CAM.camdist*s.scale
	if GS.camadd
		if CAM.loopcam
			CAM.restoreANG = CAM.angle
			CAM.angle = $+GS.camadd	
		elseif not ((CAM.turning or 0)>8) and RO.cam_shift and not CAM.spawntic --Sideways camera shift
			local ADD = FixedDiv(FixedMul(GS.camadd, RO.cam_shift), 10)
			ANGCAM = $+ADD
			CAM.restoreANG = CAM.angle			
			CAM.angle = $+(ADD/2)
			if (abs(ADD) >= ANG2)
				CAMDIST = $+abs((ADD/ANG2)*s.scale)
			end 
		end
	end
	if (LSIDECAM) and LOOP and LOOP.walljump
		local SETZ = CAM.z
		if GS.grinding --Not when jumping!
		and (abs((s.z+s.momz)-CAM.z) > 400*s.scale)
			SETZ = s.z
		end
		P_MoveOrigin(CAM, s.x-FixedMul(CAMDIST*2, cos(ANGCAM)), s.y-FixedMul(CAMDIST*2, sin(ANGCAM)), SETZ)	
	elseif (CAM.loopCstart) and not (LSIDECAM) --Starting a 3D loopcam?
		CAM.stress,CAM.warptic = 0,nil
		local NANG = ANGCAM
		local X,Y,Z = s.x,s.y,CAM.z
		local TAB = CAM.CAMfXY
		local DIST = CAMDIST*3
		if TAB!=nil
			TAB.init = $+1
			X,Y = TAB.sx, TAB.sy
			DIST =  CAM.CAMfXY.DIST
			
			local DIR = -1 --(GS.railspeed < 0) and 1 or 
			local INIT = TAB.init
			local PLUS = (ANG1/4)*(min(48, INIT)*DIR)
			NANG = TAB.ANG-PLUS
			
			if CAM.loopCstart=="unlock"
				DIST = $+min(2850*s.scale, (INIT*max((GS.railspeed or 0)/2, 38*s.scale)))
				CAM.warptic = nil
				CAM.angle = R_PointToAngle2(CAM.x, CAM.y, s.x, s.y)
			else
				DIST = $+min(2000*s.scale, (INIT*24*s.scale))
			--	CAM.angle = TAB.CAMANG-PLUS
				if (INIT < 11)
					TAB.sx, TAB.sy = s.x, s.y
					if (INIT < 7)
						CAM.noZ = max(CAM.noZ or 0, 3)
					end
				end
			end
		end
		if (LOOPFLAGS & 4194304)
			NANG = $+ANGLE_180
		end
	--	print("INIT:"+INIT+" NANG:\x84"+NANG/ANG1+"\x80 DIST:\x82"+DIST/FRACUNIT)
		P_MoveOrigin(CAM, X-FixedMul(DIST, cos(NANG)), Y-FixedMul(DIST, sin(NANG)), Z)
		if TAB==nil
			 CAM.CAMfXY = {DIST = CAMDIST*4, ANG = NANG, init = 0, CAMANG = CAM.angle, sx = s.x, sy  = s.y, sz = Z}
		end
	else --Standard move camera!
		local DISTM = CAMDIST*3
		if not (P_TryMove(CAM, s.x-FixedMul(DISTM, cos(ANGCAM)), s.y-FixedMul(DISTM, sin(ANGCAM)), true))
			local DIV = 2
			CAM.warptic = 1
			for i = 1,12 --Set basic camera position! Try a big jump first, and if it didn't work, split the progress into segments.
				if not (LOOP)
					CAM.stress = CAM.stress and $+2 or 2
				end
				if (
					P_TryMove(CAM, 
					s.x-FixedMul(DISTM/DIV, cos(ANGCAM)),
					s.y-FixedMul(DISTM/DIV, sin(ANGCAM)), true)
					) break --
				else
					DIV = $+(2+i) if (DIV > 28) break end --
				end
			end
		end
	end
	if (LSIDECAM) --Always be a bit to the side!
		if not (LOOP and LOOP.walljump) --Look ahead a bit.
			local SIDEANG = p.drawangle if rail.GSVertRailDOWNANG!=nil SIDEANG = rail.GSVertRailDOWNANG+ANGLE_180 end
			local SETX,SETY = FixedMul(48*s.scale, cos(SIDEANG)) , FixedMul(48*s.scale, sin(SIDEANG))		
			P_MoveOrigin(CAM, CAM.x+SETX, CAM.y+SETY, CAM.z)
			if not GS.grinding and (s.momz*P_MobjFlip(s) > 0) and (p.pflags & (PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE))
				CAM.momz = $-(s.momz*P_MobjFlip(s))
			end
			if FORCEANG!=nil
				CAM.FORCECAM = CAM.angle 
			end
		end
	else
		if HANG==true and GS.myrail --Hanging! Move camera sideways a bit to see the player.
			if GS.camdir
				ANGCAM = $+(ANGLE_90*GS.camdir)
				CAMDIST = 12*s.scale
			else
				ANGCAM = $+(ANGLE_90*((GS.raildirection==0) and 1 or -1))
				CAMDIST = 12*s.scale
			end
			if not P_TryMove(CAM, CAM.x-FixedMul(CAMDIST, cos(MOMANG)),  CAM.y-FixedMul(CAMDIST, sin(MOMANG)), true) 
				local DIV = 2
				CAM.warptic = 1
				for i = 1,9  --Couldn't do it in 1 go, so performance to the wind!
					if not P_TryMove(CAM, CAM.x-FixedMul(CAMDIST/DIV, cos(MOMANG)), CAM.y-FixedMul(CAMDIST/DIV, sin(MOMANG)), true) 
						DIV = $+(2+i)
					else
						break --
					end
				end
			end 
		end
		if not CAM.warptic and not CAM.spawntic
			local X,Y,Z = CAM.x,CAM.y,CAM.z
			if not P_TryMove(CAM, CAM.x+FixedMul(200*s.scale, cos(ANGCAM)), CAM.y+FixedMul(200*s.scale, sin(ANGCAM)), true) 
				P_SetOrigin(CAM, X,Y,Z)
				CAM.warptic = 1
			end
		end	
		if GS.myrail and GS.myrail.GSinvisiblerail and (HANG!=true) and CAM.spawntic==nil --Adjust so they can see the "rail" better.
			local ANG = MOMANG+ ( ANGLE_90*((GS.railspeed<0) and -1 or 1) )
			for i = 1,2
				P_TryMove(CAM, CAM.x+FixedMul(14*s.scale, cos(ANG)), CAM.y+FixedMul(14*s.scale, sin(ANG)), true)
			end
		end		
	end	
	CAM.zspeed = (((HANG==true) and 39 or 31)-min(20, GS.grinding or 0))*s.scale --Reset every tic.
	CAM.PlastZ = s.z --For slope calculations.
	GS.lastPang = p.cmd.angleturn<<16	
	if CAM.spawntic
		CAM.spawntic = nil		
	else
		if not (GS.chasecam==false)
			p.cmd.angleturn = CAM.angle>>16
			s.angle = CAM.angle
		end
		if CAM.superturn
			CAM.superturn = $-1
		end
		if CAM.instaturn and not ((GS.railfalltimer or 0) > 13)
			CAM.instaturn = $-1
		end
		if CAM.dimROD
			local DIMROD = CAM.dimROD
			DIMROD.init,DIMROD.timer = $+1,$-1
			if not DIMROD.timer CAM.dimROD = nil end	
		end			
		if LOOP
			CAM.turnstress = nil
			if LSIDECAM
				CAM.noZ,CAM.loopcam = nil --Not the same loopcam!
			elseif CAM.loopcam
				CAM.loopcam = max($-1, 0)
			end
		else
			if ((GS.railfalltimer or 0) > 13) and GS.grinding and not ((LOOPFLAGS & (262144|524288)) and not (LOOPFLAGS & 4194308))
				s.rollangle = GS.rollangle or 0
			end
			CAM.loopCstart,CAM.loopcam,CAM.loopstart,CAM.CAMfXY = nil
			if CAM.turnstress
				if not GS.grinding
					CAM.turnstress = 0
				else
					CAM.turnstress = max(0, min(151, $-1))
					if ((CAM.turning or 0)>9) and CAM.turnstress 
						CAM.turnstress = $/2
					end
				end
			end
		end
		if CAM.noZ --Don't do any Z checks this tics?
			CAM.noZ = $-1
		end
		if p==ME
			if (LOOPFLAGS & (262144|524288|131072))  --Loop Rollangling! Requires sidecam!
			and (CAM.FORCEANG!=nil or (LOOP and not LOOP.walljump and LSIDECAM))
			and GS.grinding and not (LOOPFLAGS & 4194304) --Not on front cameras!
				s.frame = $ & ~FF_VERTICALFLIP
			--	print("1:\x82 "+(CAM.FORCEANG)+"\x80 LOOPFLAGS:\x82"+LOOPFLAGS+"\x80 GS.grinding:\x84"+GS.grinding)
				if (s.sprite2 & ~SS2)==SPR2_ROLL or GS.forcesprite==SPR2_ROLL
					s.rollangle = 0	
				elseif rail	
					local USEANG = CAM.FORCEANG if USEANG==nil USEANG = CAM.angle end
					local ANGDIFF,PLUS = RAIL.AngleDifference(USEANG, p.drawangle, 2, ANGLE_90, 2)
					if RSTATS and RSTATS.VERTRAIL --Duh.
						s.rollangle = ANGLE_90*(PLUS*RAIL.GrindFlip(s, rail)*(GS.reversing or 1))
					elseif (LOOPFLAGS & (262144|524288)) or (LSIDECAM)
						PLUS = $*((s.mirrored) and 1 or -1)*RAIL.GrindFlip(s, rail)*(GS.reversing or 1)
						if (LOOPFLAGS & 131072) --Upside down? Flip sprite in 2D!
							s.frame = $|FF_VERTICALFLIP
							PLUS = -$
						end
						if rail.GSrailsideL and rail.GSrailsideL.valid and rail.GSrailsideL.rollangle!=nil
							s.rollangle = rail.GSrailsideL.rollangle*PLUS
						elseif rail.GSrailZDelta --Uhh, we'll use this, then?
							s.rollangle = rail.GSrailZDelta*PLUS
						end
					end
				end
			else
				local ANG = RAIL.AngleDifference(MOMANG, CAM.angle, 2, ANGLE_90, 2)
				if (netgame!=true) and camera and camera.chase and (GS.chasecam!=false) 
					P_TeleportCameraMove(camera, CAM.x, CAM.y, CAM.z)
					camera.angle = CAM.angle
				end
				if GS.rollangle!=nil and (GS.grinding) --Normal grinding rollangle.	
					local PLUS = 1
					if s.mirrored
						PLUS = -1
					--	if CV_FindVar("renderer").value==2 and CV_FindVar("gr_models").string=="On"
					--		PLUS = 1 --Nope. Can't actually determine if player is using a model this way...
					--	end
					end
					if (LOOPFLAGS & 4194304) --Flip from the front.
						PLUS = $*-1
					end
					if (ANG > ANG2*36)
						s.rollangle = ((GS.rollangle or 1)/-2 or 0)*PLUS 
					elseif not (ANG > ANG2*16)
						s.rollangle = (GS.rollangle or 0)*PLUS 
					end
				end
			end
		end	
	end
	return CAM --
end